#pragma version(1)

#pragma rs java_package_name(at.knorre.swipebeam)

#include "rs_graphics.rsh"
#pragma stateVertex(parent);
#pragma stateStore(parent);

rs_allocation textureDot;
rs_allocation textureBeam;

rs_program_vertex vertBg;
rs_program_fragment fragBg;

rs_program_vertex vertDots;
rs_program_fragment fragDots;

static int numBeamParticles;
static int numDotParticles;
static int numVertColors;

typedef struct __attribute__((packed, aligned(4))) Particle {
    float3 position;
    float offsetX;
} Particle_t;

typedef struct VpConsts {
    rs_matrix4x4 MVP;
    float scaleSize;
} VpConsts_t;
VpConsts_t *vpConstants;

typedef struct VertexColor_s {
    float3 position;
    float offsetX;
    float4 color;
} VertexColor;

VertexColor* vertexColors;
Particle_t *dotParticles;
Particle_t *beamParticles;
rs_mesh dotMesh;
rs_mesh beamMesh;
rs_mesh gBackgroundMesh;

float densityDPI;
float xOffset = 0.5;
int passed = 0;
int touched = 0;

static float screenWidth;
static float screenHeight;
static float halfScreenWidth;
static float quarterScreenWidth;
static float quarterScreenHeight;
static float halfScreenHeight;

static float newOffset = 0.5;
static float oldOffset = 0.5;

void positionParticles() {
    screenWidth = rsgGetWidth();
    screenHeight = rsgGetHeight();
    halfScreenWidth = screenWidth/2.0f;
    halfScreenHeight = screenHeight/2.0f;
    quarterScreenWidth = screenWidth/4.0f;
    quarterScreenHeight = screenHeight/4.0f;
    rs_allocation aParticles = rsGetAllocation(dotParticles);
    numDotParticles = rsAllocationGetDimX(rsGetAllocation(dotParticles));
    numVertColors = rsAllocationGetDimX(rsGetAllocation(vertexColors));
    for(int i=0; i<numDotParticles; i++) {
        Particle_t* particle = (Particle_t *) rsGetElementAt(aParticles, i);
        particle->position.x = rsRand(0.0f, 3.0f);
        particle->position.y = rsRand(-1.25f, 1.25f);

        float z;
        if (i < 3) {
            z = 14.0f;
        } else if(i < 7) {
            z = 25.0f;
        } else if(i < 4) {
            z = rsRand(10.f, 20.f);
        } else if(i == 10) {
            z = 24.0f;
            particle->position.x = 1.0;
        } else {
            z = rsRand(6.0f, 14.0f);
        }
        particle->position.z = z;
        particle->offsetX = 0;
    }

    Particle_t* beam = beamParticles;
    numBeamParticles = rsAllocationGetDimX(rsGetAllocation(beamParticles));
    for(int i=0; i<numBeamParticles; i++) {
        float z;
        if(i < 20) {
            z = rsRand(4.0f, 10.0f)/2.0f;
        } else {
            z = rsRand(4.0f, 35.0f)/2.0f;
        }
        beamParticles->position.x = rsRand(-1.25f, 1.25f);
        beamParticles->position.y = rsRand(-1.05f, 1.205f);

        beamParticles->position.z = z;
        beamParticles->offsetX = 0;
        beamParticles++;
    }
}

int root() {
	int wait = 32;
    newOffset = xOffset*2;
    rsgClearColor(0.0f, 0.f, 0.f,1.0f);

    if(newOffset != oldOffset) {
        VertexColor* vert = vertexColors;
        for(int i=0; i<numVertColors; i++) {
            vert->offsetX = -xOffset/2.0;
            vert++;
        }
    }

    rsgBindProgramVertex(vertBg);
    rsgBindProgramFragment(fragBg);

    rsgDrawMesh(gBackgroundMesh);

    Particle_t* beam = beamParticles;
    Particle_t* particle = dotParticles;

	if (passed == 0) {
	    for(int i=0; i<numDotParticles; i++) {
	
	        if(newOffset==oldOffset) {
	            if(beam->position.x/beam->position.z > 0.5) {
	                beam->position.x = -1.0;
	            }
	            if(particle->position.x/particle->position.z > 0.5) {
	                particle->position.x = -1.0;
	            }
	
	            if(beam->position.y > 1.05) {
	                beam->position.y = -1.05;
	                beam->position.x = rsRand(-1.25f, 1.25f);
	            } else {
	                beam->position.y = beam->position.y + 0.00009*beam->position.z;
	            }
	            if(particle->position.y > 1.25) {
	                particle->position.y = -1.25;
	                particle->position.x = rsRand(0.0f, 3.0f);
	
	            } else {
	                particle->position.y = particle->position.y + 0.0001*particle->position.z;
	            }
	        }
	
	        beam->position.x = beam->position.x + 0.00005*beam->position.z;
	        beam->offsetX = newOffset;
	        beam++;
	        particle->offsetX = newOffset;
	        particle->position.x = particle->position.x + 0.00002*particle->position.z;
	        particle++;
	    }
	}

    rsgBindProgramVertex(vertDots);
    rsgBindProgramFragment(fragDots);

    rsgBindTexture(fragDots, 0, textureBeam);
    rsgDrawMesh(beamMesh);

    rsgBindTexture(fragDots, 0, textureDot);
    rsgDrawMesh(dotMesh);

	if (touched || newOffset != oldOffset)
    	wait = 16;
    
    oldOffset = newOffset;
    	
    passed += wait;
    if (passed >= 32)
    	passed = 0;
    	
    return wait;

}